﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;

namespace SharpSoft.WPF.Controls
{
    /// <summary>
    /// 自定义媒体控件，可以显示由xml定义的混合媒体内容
    /// </summary>
    public class CustomMedia : Control
    {
        static CustomMedia()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomMedia), new FrameworkPropertyMetadata(typeof(CustomMedia)));
        }
        public CustomMedia()
        {

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.border = (Border)GetTemplateChild("border");

            this.border.Child = this.canvas;
        }

        private Canvas canvas;
        private Border border;
        /// <summary>
        /// 媒体源
        /// </summary>
        public Uri Source
        {
            get { return (Uri)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(Uri), typeof(CustomMedia), new PropertyMetadata(null));

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == SourceProperty)
            {
                if (this.Source == null)
                {
                    this.canvas = null;
                }
                else
                {
                    this.canvas = LoadCustomMediaFile(this.Source.ToString());
                }

                if (this.border != null)
                {
                    this.border.Child = this.canvas;
                }
            }
        }

        #region Static


        /// <summary>
        /// 加载自定义媒体文件,并将其生成运行时控件添加到一个Canvs中
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static Canvas LoadCustomMediaFile(string filename)
        {
            List<IMediaNode> medias = new List<IMediaNode>();
            XDocument doc = XDocument.Load(filename);
            if (doc.Root.Name == "Root")
            {
                foreach (var child in doc.Root.Elements())
                {
                    if (child.NodeType == System.Xml.XmlNodeType.Element)
                    {
                        IMediaNode node = null;
                        if (child.Name == "Image")
                        {//图片节点
                            ImageNode imageNode = new ImageNode();
                            node = imageNode;
                        }
                        else if (child.Name == "Video")
                        {//视频节点
                            VideoNode videoNode = new VideoNode();
                            node = videoNode;
                        }
                        ReadPublicAttribute(child, node);
                        medias.Add(node);
                    }
                }
                Canvas canvas = new Canvas();
                var baseUri = new Uri( filename );
                foreach (var item in medias)
                {
                    var ctrl = item.ToRuntimeControl(baseUri);
                    canvas.Children.Add(ctrl);
                    RelativePosition.SetPosition(ctrl, item.Position);
                    RelativePosition.SetSize(ctrl, item.Size);
                }
                return canvas;
            }
            else
            {
                throw new Exception("自定义媒体文件的根节点应为“Root”。");
            }
        }

        /// <summary>
        /// 从节点读取公有的属性
        /// </summary>
        /// <param name="element"></param>
        /// <param name="node"></param>
        private static void ReadPublicAttribute(XElement element, IMediaNode node)
        {
            var posattr = element.Attribute("Position");
            if (posattr != null)
            {
                try
                {
                    node.Position = Point.Parse(posattr.Value);
                }
                catch (Exception)
                {
                    throw new Exception($"[{posattr.Value}]无法转换为有效的坐标数据，正确的坐标格式应为：[x,y]。");
                }

            }
            var sizeattr = element.Attribute("Size");
            if (sizeattr != null)
            {
                try
                {
                    node.Size = Size.Parse(sizeattr.Value);
                }
                catch (Exception)
                {
                    throw new Exception($"[{posattr.Value}]无法转换为有效的尺寸数据，正确的尺寸格式应为：[width,height]。");
                }
            }
            var souattr = element.Attribute("Source");
            if (souattr != null)
            {
                node.Source = souattr.Value;
            }
            var stretchattr = element.Attribute("Stretch");
            if (stretchattr != null)
            {
                EnumConverter ec = new EnumConverter(typeof(Stretch));
                try
                {
                    node.Stretch = (Stretch)ec.ConvertFromInvariantString(stretchattr.Value);
                }
                catch (Exception)
                {
                    throw new Exception($"[{stretchattr.Value}]不能转为有效的媒体拉伸方式，有效的值为：[Fill(填充) | Uniform（适应宽高） | UniformToFill（适应宽高并填充） |None（不拉伸，使用源媒体的大小）]。");
                }

            }
            else
            {
                node.Stretch = Stretch.Fill;
            }
        }

        #endregion

        #region InnerClass


        /// <summary>
        /// 自定义媒体节点接口
        /// </summary>
        public interface IMediaNode
        {
            /// <summary>
            /// 媒体出现的位置坐标，使用百分比坐标。
            /// </summary>
            Point Position { get; set; }
            /// <summary>
            /// 媒体展示的尺寸，使用百分比尺寸
            /// </summary>
            Size Size { get; set; }
            /// <summary>
            /// 媒体文件位置，相对于当前自定义媒体文件的位置。
            /// </summary>
            string Source { get; set; }
            /// <summary>
            /// 媒体文件的填充方式
            /// </summary>
            Stretch Stretch { get; set; }
            /// <summary>
            /// 生成运行时控件
            /// </summary>
            /// <returns></returns>
            FrameworkElement ToRuntimeControl(Uri baseUri);
        }
        /// <summary>
        /// 视频节点
        /// </summary>
        public class VideoNode : IMediaNode
        {
            public Point Position { get; set; }

            public Size Size { get; set; }

            public string Source { get; set; }

            public Stretch Stretch { get; set; }

            public bool AutoPlay { get; set; }

            public bool AutoReplay { get; set; }

            public TimeSpan? StayWhenStop { get; set; }

            public FrameworkElement ToRuntimeControl(Uri baseUri)
            {
                return new VideoPlayer()
                {
                    Stretch = this.Stretch,
                    AutoPlay = this.AutoPlay,
                    AutoReplay = this.AutoReplay,
                    StayWhenStop = this.StayWhenStop,
                    Source = new Uri(baseUri, this.Source),
                };
            }
        }
        /// <summary>
        /// 图片节点
        /// </summary>
        public class ImageNode : IMediaNode
        {
            public Point Position { get; set; }

            public Size Size { get; set; }

            public string Source { get; set; }

            public Stretch Stretch { get; set; }

            public FrameworkElement ToRuntimeControl(Uri baseUri)
            {
                return new Image()
                {
                    Source = new BitmapImage(new Uri(baseUri, this.Source)),
                    Stretch = this.Stretch,
                };
            }
        }
        #endregion
    }
}
